package org.itzheng.myrxframe.upt;

import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.support.v4.content.FileProvider;

import org.itzheng.and.baseutils.json.JsonHelper;
import org.itzheng.and.baseutils.log.LogHelper;
import org.itzheng.myrxframe.R;
import org.itzheng.myrxframe.http.ApiUrl;
import org.itzheng.myrxframe.http.retrofit.interceptor.DownloadInterceptor;
import org.itzheng.myrxframe.http.retrofit.interceptor.LogInterceptor;
import org.itzheng.myrxframe.http.retrofit.utils.ApiServiceUtils;
import org.itzheng.myrxframe.http.retrofit.utils.FileManager;
import org.itzheng.myrxframe.http.retrofit.utils.RetrofitClient;
import org.itzheng.myrxframe.http.rxjava.RxHelper;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;

/**
 * Title:版本更新工具<br>
 * Description: <br>
 *
 * @email ItZheng@ZoHo.com
 * Created by itzheng on 2019-4-11.
 */
public class VersionUpt {
    public static VersionUpt newInstance() {
        return new VersionUpt();
    }

    /**
     * @param uptUrl   检查更新的Url
     * @param activity
     * @return
     */
    public <T> VersionUpt checkUtpUrl(String uptUrl, Activity activity) {
//        return checkUtpUrl(uptUrl, new DefCheckVersionResult(activity));
        return null;
    }

    /**
     * @param uptUrl 检查更新的Url
     * @param result
     * @return
     */
    public <T> VersionUpt checkUtpUrl(String uptUrl, CheckVersionResult<T> result, Class<T> clazz) {
        ApiServiceUtils.create(true, UtpApiService.class).getUrl(uptUrl).
                compose(RxHelper.observableIO2Main())
                .map(new Function<ResponseBody, T>() {
                    @Override
                    public T apply(ResponseBody responseBody) throws Exception {
                        return JsonHelper.fromJson(responseBody.string(), clazz);
                    }
                })
                .subscribe(new Consumer<T>() {
                    @Override
                    public void accept(T t) throws Exception {
                        if (result != null) {
                            result.onSuccess(VersionUpt.this, t);
                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        if (result != null) {
                            result.onError(throwable.toString());
                        }
                    }
                });
        return this;
    }

    private static final String TAG = "VersionUpt";

    /**
     * 开始下载Apk包
     *
     * @param url
     */
    public VersionUpt startDownloadApk(String url) {
        OkHttpClient.Builder builder = new OkHttpClient().newBuilder()
                .readTimeout(ApiUrl.DEFAULT_SECONDS_TIME_OUT, TimeUnit.SECONDS)//设置读取超时时间
                .connectTimeout(ApiUrl.DEFAULT_SECONDS_TIME_OUT, TimeUnit.SECONDS)//设置请求超时时间
                .writeTimeout(ApiUrl.DEFAULT_SECONDS_TIME_OUT, TimeUnit.SECONDS)//设置写入超时时间
                .addInterceptor(new DownloadInterceptor(new DownloadInterceptor.DownloadProgressListener() {
                    @Override
                    public void progress(long read, long contentLength, boolean done) {
                        //这个在子线程执行
                        //切换到主线程执行
                        updateProgressOnMain(read, contentLength, done);
                    }
                }))//添加打印拦截器
                .retryOnConnectionFailure(true);//设置出现错误进行重新连接。
        ApiServiceUtils.create(builder.build(), UtpApiService.class).download("0", url)
                .subscribeOn(Schedulers.io())
                .map(new Function<ResponseBody, String>() {
                    @Override
                    public String apply(ResponseBody responseBody) throws Exception {
                        LogHelper.w(TAG, Thread.currentThread().getName() + "apply：");
                        return saveBytesByIO(url, responseBody);
                    }
                }).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        if (mDownloadCallback != null) {
                            mDownloadCallback.onStart();
                        }
                    }

                    @Override
                    public void onNext(String value) {
//                        LogHelper.w(TAG, Thread.currentThread().getName() + "accept: 文件保存路径" + value);
                        if (mDownloadCallback != null) {
                            mDownloadCallback.onSuccess(value);
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        if (mDownloadCallback != null) {
                            mDownloadCallback.onError(e.toString(), new Exception(e));
                        }
                    }

                    @Override
                    public void onComplete() {

                    }
                });
        return this;
    }

    /**
     * 更新进度
     *
     * @param read
     * @param contentLength
     * @param done
     */
    private void updateProgressOnMain(long read, long contentLength, boolean done) {
        Observable.just(0).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        //在主线程更新
//                        LogHelper.w(TAG, Thread.currentThread().getName() + " " + read + "/" + contentLength);
                        if (mDownloadCallback != null) {
                            mDownloadCallback.onProgress(read, contentLength);
                        }
                    }
                });
    }

    private String saveBytesByIO(String url, ResponseBody responseBody) throws Exception {
        String filename = url.substring(url.lastIndexOf('/') + 1);
        File file = new File(FileManager.getCacheDir(), filename);
//        LogHelper.w(TAG, "file:" + file.getAbsolutePath());
        byte[] bytes = responseBody.bytes();
//        LogHelper.w(TAG, "bytes length:" + bytes.length);
        if (FileManager.saveBytesToFile(bytes, file)) {
            return file.getPath();
        } else {
            throw new Exception("file save Exception");
        }
    }

    /**
     * 下载监听
     */
    private IDownloadCallback mDownloadCallback;

    /**
     * 设置下载进度回调
     *
     * @param downloadCallback
     * @return
     */
    public VersionUpt setDownloadCallback(IDownloadCallback downloadCallback) {
        mDownloadCallback = downloadCallback;
        return this;
    }

    /**
     * 下载进度回调
     */
    public interface IDownloadCallback {
        public void onStart();

        public void onProgress(long progress, long total);

        public void onSuccess(String file);

        public void onError(String error, Exception e);
    }


    public interface CheckVersionResult<T> {
        void onSuccess(VersionUpt versionUpt, T t);

        void onError(String error);
    }

    /**
     * 默认下载回调
     */
    public static class DefDownloadCallback implements IDownloadCallback {
        private Activity mActivity;
        private ProgressDialog progressDialog;

        public DefDownloadCallback(Activity activity) {
            mActivity = activity;
            progressDialog = new ProgressDialog(activity, R.style.Widget_AppCompat_ProgressBar_Horizontal);
            progressDialog.setMax(100);
//            progressDialog.setProgressStyle();
        }

        @Override
        public void onStart() {
            progressDialog.show();
            progressDialog.setMessage("onStart");
        }

        @Override
        public void onProgress(long progress, long total) {
            progressDialog.setMessage(progress + "/" + total);
            progressDialog.setProgress((int) (progress * 100 / total));
        }

        @Override
        public void onSuccess(String file) {
            progressDialog.setMessage("onSuccess");
            progressDialog.dismiss();
            VersionUpt.installApk(mActivity, file);
        }

        @Override
        public void onError(String error, Exception e) {
            progressDialog.setTitle("onError");
            progressDialog.setMessage(error);

        }
    }

    /**
     * 默认检查回调，使用默认对话框提示是否更新
     */
    public static class DefCheckVersionResult implements CheckVersionResult<VersionInfo> {
        public DefCheckVersionResult(Activity activity) {

        }

        @Override
        public void onSuccess(VersionUpt versionUpt, VersionInfo versionInfo) {
            versionUpt.startDownloadApk(versionInfo.url);
        }

        @Override
        public void onError(String error) {

        }

    }

    /**
     * 安装APK
     *
     * @param apkUri apk文件的uri，如：Uri.fromFile(file)
     */
    public static void installApk(Context context, Uri apkUri) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        // 由于没有在Activity环境下启动Activity,设置下面的标签
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        // 添加这一句表示对目标应用临时授权该Uri所代表的文件
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
        context.startActivity(intent);
    }

    /**
     * 安装APK
     *
     * @param apkUri apk文件的uri，如：Uri.fromFile(file)
     */
    public static void installApk(Context context, String apkUri) {
        installApk(context, getUriForFile(context, new File(apkUri)));
    }

    private static Uri getUriForFile(Context context, File file) {
        if (file == null) {
            throw new NullPointerException();
        }
        Uri uri;
        if (Build.VERSION.SDK_INT >= 24) {
            uri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileProvider", file);
        } else {
            uri = Uri.fromFile(file);
        }
        return uri;
    }
}
